package com.hst.capacity.domain.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.anno.CacheRefresh;
import com.alicp.jetcache.anno.CacheUpdate;
import com.hst.capacity.domain.exception.BusinessException;
import com.hst.capacity.domain.model.entity.auth.UserEntity;
import com.hst.capacity.domain.model.entity.franchisee.FranchiseeUserEntity;
import com.hst.capacity.domain.model.request.franchisee.FranchiseeUserParam;
import com.hst.capacity.domain.model.request.franchisee.FranchiseeUserListParam;
import com.hst.capacity.domain.model.response.PagingResultVO;
import com.hst.capacity.domain.model.response.franchisee.FranchiseeUserVO;
import com.hst.capacity.domain.service.FranchiseeUserService;
import com.hst.capacity.infra.convertor.FranchiseeConvertor;
import com.hst.capacity.infra.convertor.UserConvertor;
import com.hst.capacity.infra.persistence.jpa.UserRepository;
import com.hst.capacity.infra.persistence.jpa.franchisee.FranchiseeUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

@Service
public class FranchiseeUserServiceImpl implements FranchiseeUserService {

    @Autowired
    private FranchiseeUserRepository franchiseeUserRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserRepository userRepository;

    @Override
    public FranchiseeUserEntity save(FranchiseeUserParam param) {

        UserEntity userEntity;
        FranchiseeUserEntity franUserEntity = UserConvertor.INSTANCE.convert(param);
        UserEntity entity = userRepository.findUserEntityByUsername(param.getUsername());
        List<UserEntity> byMobile = userRepository.findByMobile(param.getMobile());
        boolean isExist = (entity != null);
        //编辑用户
        if (StrUtil.isNotEmpty(param.getId())){
            if (!isExist) {
                throw new BusinessException(5002,"编辑的对象不存在，请检查");
            }

            if (isExist) {
                franUserEntity.setUser(entity);
                franUserEntity.getUser().setMobile(param.getMobile());
                franUserEntity.getUser().setUserStatus(param.getUserStatus());
                franUserEntity.getUser().setUserType(param.getUserType());
                franUserEntity.setIdFranchisee(param.getIdFranchisee());
                franUserEntity.setUserType(param.getUserType());
                franUserEntity.setDisplayName(param.getRealName());
            }
        } else {
            //创建用户
            if (isExist)
                throw new BusinessException(5002,"用户名已存在,请重新添加");

            franUserEntity.getUser().setUserPassword(passwordEncoder.encode(param.getPassword()));
        }

        return franchiseeUserRepository.save(franUserEntity);
    }

    @Override
    public FranchiseeUserEntity edit(FranchiseeUserParam param) {

        UserEntity userEntity;
        FranchiseeUserEntity franUserEntity = UserConvertor.INSTANCE.convert(param);
        UserEntity entity = userRepository.findUserEntityByUsername(param.getUsername());
        List<UserEntity> byMobile = userRepository.findByMobile(param.getMobile());
        boolean isExist = (entity != null);
        if (!isExist) {
            throw new BusinessException(5002,"编辑的对象不存在，请检查");
        }

        //编辑用户
        entity.setMobile(param.getMobile());
        updateUser(entity);
        franUserEntity.setUser(entity);
        franUserEntity.setIdFranchisee(param.getIdFranchisee());
        franUserEntity.setUserType(entity.getUserType());
        franUserEntity.setDisplayName(param.getRealName());

        return franchiseeUserRepository.save(franUserEntity);
    }

    @CacheUpdate(name="users", key="#user.id", value="#user")
    public void updateUser(UserEntity user) {
        return;
    }

    @Override
    public PagingResultVO list(FranchiseeUserListParam param) {
        Page<FranchiseeUserEntity> page = franchiseeUserRepository.findAll(new Specification<FranchiseeUserEntity>() {
            @Override
            public Predicate toPredicate(Root<FranchiseeUserEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                // 定义条件LIST
                List<Predicate> predicates = new ArrayList<Predicate>();
                //mobile
                if (ObjectUtil.isNotEmpty(param.getUserMobile())) {
                    predicates.add(criteriaBuilder.equal(root.get("user").get("mobile"),param.getUserMobile()));
                }
                //username
                if (ObjectUtil.isNotEmpty(param.getUserName())) {
                    predicates.add(criteriaBuilder.equal(root.get("user").get("username"),param.getUserName()));
                }
                //full_name
                if (ObjectUtil.isNotEmpty(param.getUserName())) {
                    predicates.add(criteriaBuilder.like(root.get("franchiseeEntity").get("fullName"),param.getUserName()));
                }
                // userStatus
                if (StrUtil.isNotEmpty(param.getStatus())) {
                    List<Integer> strings = Convert.toList(Integer.class, param.getStatus());
                    CriteriaBuilder.In<Integer> in = criteriaBuilder.in(root.get("user").get("userStatus"));
                    for (Integer v:strings) {
                        in.value(v);
                    }
                    predicates.add(criteriaBuilder.and(in));
                }

                //排序
                query.orderBy(criteriaBuilder.desc(root.get("createTime")));
                Predicate[] array = predicates.toArray(new Predicate[0]);
                return criteriaBuilder.and(array);
            }
        }, PageRequest.of(param.getPageIndex()-1,param.getPageSize()));

        return new PagingResultVO(page.getTotalElements(),page.getContent());
    }

    @Override
    public FranchiseeUserEntity getFranchiseeUser(UserEntity user) {
        return franchiseeUserRepository.findByUser(user);
    }

    @Override
    public FranchiseeUserEntity getFranchiseeUser(String userId) {
        return franchiseeUserRepository.findByUserId(userId);
    }

    @Override
    public FranchiseeUserVO select(String idFranchiseeUser) {
        return FranchiseeConvertor.INSTANCE.convert(franchiseeUserRepository.findById(idFranchiseeUser).get());
    }

}
